package my.mark.mybaibaoxiang.nhr.codeToName;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
//import org.apache.commons.collections.ListUtils;
import org.springframework.util.CollectionUtils;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.*;

public class ClassUtil {

    /**
     * 判断对象是否集合类型
     *
     * @param c
     * @return boolean
     */
    public static boolean isClassCollectionOrMap(Class c) {
        return Collection.class.isAssignableFrom(c) || Map.class.isAssignableFrom(c);
    }

    /**
     * 是否是map类型
     *
     * @param c
     * @return boolean
     */
    public static boolean isClassMap(Class c) {
        return Map.class.isAssignableFrom(c);
    }

    /**
     * 是否是Collection类型
     *
     * @param c
     * @return boolean
     */
    public static boolean isClassCollection(Class c) {
        return Collection.class.isAssignableFrom(c);
    }

    public static boolean compareObject(Object oldObject, Object newObject) throws Exception {
        Map<String, Map<String, Object>> resultMap = compareFields(oldObject, newObject);

        if (resultMap.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public static Map<String, Map<String, Object>> compareFields(Object oldObject, Object newObject) throws Exception {
        Map<String, Map<String, Object>> map = new HashMap<>(8);
        /**
         * 只有两个对象都是同一类型的才有可比性
         */
        if (oldObject.getClass() == newObject.getClass()) {
            map = new HashMap<String, Map<String, Object>>();

            Class clazz = oldObject.getClass();
            // 获取object的所有属性
            PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();

            for (PropertyDescriptor pd : pds) {
                // 遍历获取属性名
                String name = pd.getName();
                Field field = ReflectUtil.getField(newObject.getClass(), name);
                if (field != null) {
                    Ignore ignore = field.getAnnotation(Ignore.class);
                    if (ignore != null) {
                        continue;
                    }
                }
                // 获取属性的get方法
                Method readMethod = pd.getReadMethod();

                // 在oldObject上调用get方法等同于获得oldObject的属性值
                Object oldValue = readMethod.invoke(oldObject);
                // 在newObject上调用get方法等同于获得newObject的属性值
                Object newValue = readMethod.invoke(newObject);
                //注意这里没有考虑list的情况，list的情况比较复杂，暂时不处理
                //这里做统一的处理，只要是list的情况都认为是字段进行了变化
                if (oldValue == null && newValue == null) {
                    continue;
                }
                if (newValue instanceof List) {
                    if (oldValue == null && CollectionUtil.isEmpty((Collection<Object>) newValue)) {
                        continue;
                    }
                    if (CollectionUtil.isEmpty((Collection<Object>) oldValue) && CollectionUtil.isEmpty((Collection<Object>) newValue)) {
                        continue;
                    }

                    Collection<Object> esCollections = (Collection<Object>) newValue;
                    Collection<Object> omCollections = (Collection<Object>) oldValue;





                    List<Object> esFileSystemIds = new ArrayList<>();

                    for (Object esObj : esCollections) {
                        Field esField = ReflectUtil.getField(esObj.getClass(), "fileSystemId");
                        esField.setAccessible(true);
                        Object esFieldValue = esField.get(esObj);
                        esFileSystemIds.add(esFieldValue);
                    }
                    List<Object> omFileSystemIds = new ArrayList<>();
                    for (Object omObj : omCollections) {

                        Field omField = ReflectUtil.getField(omObj.getClass(), "fileSystemId");
                        omField.setAccessible(true);
                        Object omFieldValue = omField.get(omObj);
                        omFileSystemIds.add(omFieldValue);

                    }
                    // 如果esFileSystemIds和omFileSystemIds存在差集，就认为该字段有变化，PS：在此之前List属性字段都是区块证明文件，对象必然存在fileSystemId字段，一旦有所改变将不再兼容。
                    //boolean notEmpty = CollectionUtil.isNotEmpty(ListUtils.subtract(omFileSystemIds, esFileSystemIds));
                    boolean notEmpty = CollectionUtil.isNotEmpty(ClassUtil.subtract(omFileSystemIds, esFileSystemIds));
                    if (notEmpty) {
                        int i = 0;
                        Map<String, Object> valueMap = new HashMap<String, Object>();
                        valueMap.put("oldValue", null);
                        for (Object obj : esCollections) {
                            valueMap.put(i + "", compareFields(ReflectUtil.newInstance(obj.getClass()), obj));
                            i++;
                        }
                        map.put(name, valueMap);
                        continue;
                    }
                }

                if (oldValue instanceof Timestamp) {
                    oldValue = new Date(((Timestamp) oldValue).getTime());
                }

                if (newValue instanceof Timestamp) {
                    newValue = new Date(((Timestamp) newValue).getTime());
                }
                oldValue = oldValue == null ? "" : oldValue;
                newValue = newValue == null ? "" : newValue;
                // 比较这两个值是否相等,不等就可以放入map了
                if (!oldValue.equals(newValue)) {
                    Map<String, Object> valueMap = new HashMap<String, Object>();
                    valueMap.put("oldValue", oldValue);
                    valueMap.put("newValue", newValue);
                    map.put(name, valueMap);
                }
            }
        }
        return map;
    }

    public static List subtract(List list1, List list2) {
        ArrayList result = new ArrayList(list1);
        Iterator iterator = list2.iterator();

        while(iterator.hasNext()) {
            result.remove(iterator.next());
        }

        return result;
    }
}
